#include "ahxgwnet.h"

namespace ahxgwnet {

/**
 * 构造函数 创建套接字 地址初始化
 */
Socket::Socket()
{
    m_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin_family = AF_INET;
    m_addrLen = sizeof(m_addr);
}

/**
 * 析够函数 关闭连接
 */
Socket::~Socket()
{
    close();
}

/**
 * 建立TCP连接
 *
 * @param *ip 目标ip地址
 * @param port 目标端口号
 * @return 是否连接成功 1成功 0失败
 */
bool Socket::connect(const char *ip, int port)
{
    m_addr.sin_port = htons(port);
    inet_pton(AF_INET, ip, &m_addr.sin_addr.s_addr);
    
    int rc = ::connect(m_s, (SA *) &m_addr, sizeof(m_addr));
    
    return !rc;
}

/**
 * 服务器绑定端口
 *
 * @param port 服务器监听端口号
 * @return 是否绑定成功 1成功 0失败
 */
bool Socket::bind(int port)
{
    m_addr.sin_port = htons(port);
    m_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    int rc = ::bind(m_s, (SA *) &m_addr, sizeof(m_addr));
    
    return !rc;
}

/**
 * 服务器开始监听
 *
 * @param backLog 最大未被accept连接的队列长度
 * @return 是否监听成功 1成功 0失败
 */
bool Socket::listen(int backLog)
{
    int rc = ::listen(m_s, backLog);
    
    return !rc;
}

/**
 * 服务器接收一个连接
 *
 * @param &cli 新连接的引用
 * @return accept返回的描述符
 */
int Socket::accept(Socket &cli)
{
    int rc = ::accept(m_s, (SA *) &cli.m_addr, &m_addrLen);
    
    cli.m_s = rc;
    
    return rc;
}

/**
 * 获取本地ip地址
 *
 * @param &ip 保存获取到的ip
 * @return 是否获取成功 1成功 0失败
 */
bool Socket::getSockName(std::string &ip)
{
    SAI addr;
    socklen_t addrLen = sizeof(addr);
    char *p;
    
    int rc = getsockname(m_s, (SA *) &addr, &addrLen);
    
    inet_ntop(AF_INET, (SA *) &addr, p, addrLen);
    ip = p;
    
    return !rc;
}

/**
 * 获取对方ip地址
 *
 * @param &ip 保存获取到的ip
 * @return 是否获取成功 1成功 0失败
 */
bool Socket::getPeerName(std::string &ip)
{
    SAI addr;
    socklen_t addrLen = sizeof(addr);
    char *p;
    
    int rc = getpeername(m_s, (SA *) &addr, &addrLen);
    
    inet_ntop(AF_INET, (SA *) &addr, p, addrLen);
    ip = p;
    
    return !rc;
}

bool Socket::setReuseAddress()
{
    bool on = 1;
    return setIntOption(SO_REUSEADDR, on ? 1 : 0);
}

bool Socket::setIntOption(int option, int value)
{
    return !setsockopt(m_s, SOL_SOCKET, option, (const void *)(&value), sizeof(value));
}

/**
 * 关闭套接字
 */
void Socket::close()
{
    ::close(m_s);
}

}
